from django.shortcuts import render

# Create your views here.
from rest_framework.response import Response

from goods.models import SKU
from users.serializers import SKUSerializer

"""


0. 通过传递toke进行判断

    request.user  还需要判断 用户的登录状态


1. 登录用户保存在后端 redis
    未登录用户保存在 cookie


2. cookie数据(后端) 保存的信息有: 商品id(sku_id),数量(count),选中状态(selected)


3. redis保存的时候 数据类型的选取
    Redis的数据是保存在内存中的, 原则是: 占用尽量少的 数据

    因为我们每次去 判断商品是否选中的时候,都需要使用代码来判断,这个就是用代码来换取空间(Redis)

    sku_id,count,selected


hash        hash_key:  key:value
            cart_user:  sku_id:count
                     selected_sku_id:True

            cart_1      1:5


                        2:5


                        3:50


记录 选中的状态
记录选中的商品id的 我们用集合



set         set_key: value2,value5,value1,...
{1,2}



4. cookie数据的 数据格式
   {
        sku_id: {count:xxxx,selected:xxx}
        1:{count:5,selected:True}
        5:{count:50,selected:True}
        9:{count:1,selected:False}
   }

    base64
    因为base64只能处理二进制 所以我们需要将字典转换为 二进制

    dict --> pickle(转换为二进制 dumps) --> base64.b64encode (base64.b64encode.decode)

    base64.b64decode() -->pickle(loads) --> dict

     json.dumps(dict)


    base64

    1G=1024M
    1M=1024KB
    1KB = 1024B
    1B = 8bytes

    bytes 是计算机的最小单位 其实它就是 0 1

    8bytes


    0100  0001  0100  0001  0100  0001
        A           A           A


    010000      010100     000101        000001
        x           y       z               n
"""


"""
添加购物车的逻辑

当用户点击添加购物车的时候,前端应该发送一个ajax请求,包含 sku_id,count,selected(可选),token(可选)


# 1.接收数据,并且对数据进行校验
# 2.获取对应的数据
# 3.还需要判断 用户的登录状态
# 4.登录用户redis
#     4.1 连接redis
#     4.2 保存数据
#     4.3 返回响应
# 5.未登录用户cookie
#     5.1  先读取cookie数据,判断数据是否存在
#     cart = request.cookies.get('cart')
#     cart = gAN9cQBLAX1xAShYCAAAAHNlbGVjdGVkcQKIWAUAAABjb3VudHEDSwV1cy4=
#
#     5.2  更新购物车数据
#
#     dict = {}
#     5.3 我们需要对 字典进行处理 (  dict --> pickle.dumps --> base64.encode().decode())
#     response.set_cookie('cart','gAN9cQBLAX1xAShYCAAAAHNlbGVjdGVkcQKIWAUAAABjb3VudHEDSwV1cy4=')
#
#     5.4 返回响应


POST    cart/

"""
from rest_framework.views import APIView
from .serializers import CartSerializer,CartSKUSerializer
from django_redis import get_redis_connection
import base64
import pickle
class CartView(APIView):


    """
    我们的视图 如果你传递了 token 会调用视图的 perform_authentication 方法
    来验证一个用户的信息

    因为用户的token过期了 或者 token出现了伪造的情况 用户就不能够成功添加到购物车了

    应该先让用户 添加到购物车中 也就是说先不让视图调用 perform_authentication
    """

    def perform_authentication(self, request):
        pass


    def post(self,request):

        # 1.接收数据,并且对数据进行校验
        serializer = CartSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        # 2.获取对应的数据
        sku_id = serializer.validated_data.get('sku_id')
        count = serializer.data.get('count')
        selected = serializer.data.get('selected')
        # 3.还需要判断 用户的登录状态
        try:
            user = request.user
        except Exception:
            user = None

        # 判断用户是否是登录状态我们是根据 user的一个是属性
        # is_authenticated 如果为认证用户,则返回True
        # is_authenticated 如果不为认证用户,则返回False
        # request.user.is_authenticated

        if user is not None and user.is_authenticated:

            # 4.登录用户redis
            #     4.1 连接redis
            redis_conn = get_redis_connection('cart')
            #     4.2 保存数据

            # hash
            redis_conn.hset('cart_%s'%user.id,sku_id,count)
            # set
            if selected:
                redis_conn.sadd('cart_selected_%s'%user.id,sku_id)

            #     4.3 返回响应
            return Response(serializer.data)

        else:
            # 5.未登录用户cookie
            #     5.1  先读取cookie数据,判断数据是否存在
            #     cart = request.cookies.get('cart')
            #     cart = gAN9cQBLAX1xAShYCAAAAHNlbGVjdGVkcQKIWAUAAABjb3VudHEDSwV1cy4=

            cart_str = request.COOKIES.get('cart')

            if cart_str is not  None:
                #有数据
                # cart_str 先 进行  base64的解码
                decode = base64.b64decode(cart_str)
                # 再进行 将二进制转换为 字典

                cart = pickle.loads(decode)

            else:
                #没有数据
                cart = {}

            # cart = {sku_id:{count:xxx,selected:xxxx}}
            # cart = {1:{count:2,selected:True}}
            #     5.2  更新购物车数据

            #      我们需要判断 sku_id 是否在 cart中
            # 如果在cart中,我们需要对商品的count进行累加
            # 如果没有在cart中,我们添加对应的数据就可以了
            if sku_id in cart:
                # 原商品个数
                # {1:{count:2,selected:True}}
                orginal_count = cart[sku_id]['count']
                #累加
                count += orginal_count

            # cart = {1:{count:2,selected:True}}
            cart[sku_id] = {
                'count':count,
                'selected':selected
            }


            #     cart = {}
            #     5.3 我们需要对 字典进行处理 (  dict --> pickle.dumps --> base64.encode().decode())
            #     response.set_cookie('cart','gAN9cQBLAX1xAShYCAAAAHNlbGVjdGVkcQKIWAUAAABjb3VudHEDSwV1cy4=')

            # 将 cart这个字典转换为 二进制
            dumps = pickle.dumps(cart)
            # 再将二进制进行base64编码
            encode = base64.b64encode(dumps)

            # encode 是一个二进制 再进行 decode() 转换为字符串
            new_cart = encode.decode()
            #     5.4 返回响应
            response = Response(serializer.data)

            response.set_cookie('cart',new_cart,3600)

            return response

    """

       当用户点击购物车列表的时候 ,我们的前端应该发送一个ajax的请求, jwt token(请求头中)

       1.获取用户信息,根据用户信息区判断是否登录
       2.登录用户 redis
           2.1 连接redis
           2.2 获取数据 hash  set
           2.3 根据数据的id查询商品信息  [SKU,SKU,SKu]
           2.4 对数据进行序列化操作
           2.5 返回响应
       3. 未登录用户就是cookie
           3.1 从cookie中获取数据,判断数据是否存在
           cart={1:{count:xxx,selected:xxxx}}
           3.2 如果存在数据,我们要根据id 进行商品信息的查询 [SKU,SKU,SKU]
           3.3 对数据进行序列化操作
           3.4 返回响应



       1.获取用户信息,根据用户信息区判断是否登录
       2.登录用户 redis
           2.1 连接redis
           2.2 获取数据 hash  set

       3. 未登录用户就是cookie
           3.1 从cookie中获取数据,判断数据是否存在
           cart={1:{count:xxx,selected:xxxx}}

       4 如果存在数据,我们要根据id 进行商品信息的查询 [SKU,SKU,SKU]
       5 对数据进行序列化操作
       6 返回响应

       GET  /cart/
    """
    def get(self,request):
        # 1.获取用户信息,根据用户信息区判断是否登录
        try:
            user = request.user
        except Exception:
            user = None

        if user is not None and user.is_authenticated:

            # 2.登录用户 redis
            #     2.1 连接redis
            redis_conn = get_redis_connection('cart')
            #     2.2 获取数据 hash  set
            #hash
            sku_count = redis_conn.hgetall('cart_%s'%user.id)
            # {1:4,2:20,3:40}
            # set 选中的id
            selected_ids = redis_conn.smembers('cart_selected_%s'%user.id)
            # [1,2,3]

            # 因为 redis的数据和cookie的数据格式不一致,所以进行序列化操作的时候不统一
            # 我们将 redis的数据格式转换成 cookie的数据格式就可以
            # cart={1:{count:xxx,selected:xxxx},2:{count:xxx,selected:xxxx},3:{count:xxx,selected:xxxx}}
            cart = {}

            # 对 hash数据进行遍历
            for sku_id,count in sku_count.items():

                if sku_id in selected_ids:
                    selected=True
                else:
                    selected=False

                # redis的数据类型是 bytes
                # 转换一下
                cart[int(sku_id)] = {
                    'count':int(count),
                    # 'selected': sku_id in selected_ids
                    'selected': selected
                }
        else:
            # 3. 未登录用户就是cookie
            #     3.1 从cookie中获取数据,判断数据是否存在

            cookie_str = request.COOKIES.get('cart')
            if cookie_str is not None:
                #有数据
                # 先经过base64解码
                decode = base64.b64decode(cookie_str)
                # 再转换为字典
                cart = pickle.loads(decode)
            else:
                #没有数据
                cart = {}
                # cart={1:{count:xxx,selected:xxxx}}

        # cart={1:{count:xxx,selected:xxxx},2:{count:xxx,selected:xxxx}3:{count:xxx,selected:xxxx}}
        ids = cart.keys()  #[1,2,3,4,5]
        # 4 如果存在数据,我们要根据id 进行商品信息的查询 [SKU,SKU,SKU]
        skus = SKU.objects.filter(pk__in=ids)


        for sku in skus:
            #cart={1:{count:xxx,selected:xxxx}}
            sku.count=cart[sku.id]['count']
            sku.selected=cart[sku.id]['selected']

        # [SKU,SKU,SKU]
        # 5 对数据进行序列化操作
        serializer = CartSKUSerializer(skus,many=True)
        # 6 返回响应
        # 序列化操作的时候 , 序列化操作的原理是: 根据 序列化器的字段 区获取模型中数据
        # 现在模型中没有 count和selected

        return Response(serializer.data)

